package cn.stylefeng.roses.kernel.manage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.AsymmetricCrypto;
import cn.hutool.crypto.asymmetric.RSA;
import cn.stylefeng.roses.kernel.db.api.factory.PageFactory;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.entity.BaseEntity;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.manage.entity.ApiClient;
import cn.stylefeng.roses.kernel.manage.enums.ApiClientExceptionEnum;
import cn.stylefeng.roses.kernel.manage.mapper.ApiClientMapper;
import cn.stylefeng.roses.kernel.manage.pojo.request.ApiClientRequest;
import cn.stylefeng.roses.kernel.manage.pojo.response.KeyPair;
import cn.stylefeng.roses.kernel.manage.service.ApiClientService;
import cn.stylefeng.roses.kernel.rule.enums.StatusEnum;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * API客户端业务实现层
 *
 * @author fengshuonan
 * @since 2023/10/23 22:57
 */
@Service
public class ApiClientServiceImpl extends ServiceImpl<ApiClientMapper, ApiClient> implements ApiClientService {

    @Override
    public void add(ApiClientRequest apiClientRequest) {
        ApiClient apiClient = new ApiClient();
        BeanUtil.copyProperties(apiClientRequest, apiClient);
        this.save(apiClient);
    }

    @Override
    public void del(ApiClientRequest apiClientRequest) {
        ApiClient apiClient = this.queryApiClient(apiClientRequest);
        this.removeById(apiClient.getApiClientId());
    }

    @Override
    public void edit(ApiClientRequest apiClientRequest) {

        // 禁止修改应用的编码
        apiClientRequest.setApiClientCode(null);

        ApiClient apiClient = this.queryApiClient(apiClientRequest);
        BeanUtil.copyProperties(apiClientRequest, apiClient);
        this.updateById(apiClient);
    }

    @Override
    public ApiClient detail(ApiClientRequest apiClientRequest) {
        return this.queryApiClient(apiClientRequest);
    }

    @Override
    public PageResult<ApiClient> findPage(ApiClientRequest apiClientRequest) {
        LambdaQueryWrapper<ApiClient> wrapper = createWrapper(apiClientRequest);

        // 只查询关键字段
        wrapper.select(ApiClient::getApiClientId, ApiClient::getApiClientName, ApiClient::getApiClientCode,
                ApiClient::getApiClientTokenExpiration, ApiClient::getApiClientSort, ApiClient::getApiClientStatus,
                BaseEntity::getCreateTime);

        Page<ApiClient> pageList = this.page(PageFactory.defaultPage(), wrapper);
        return PageResultFactory.createPageResult(pageList);
    }

    @Override
    public KeyPair randomRsaKey() {
        RSA rsa = SecureUtil.rsa();
        AsymmetricCrypto asymmetricCrypto = rsa.initKeys();
        String publicKeyBase64 = asymmetricCrypto.getPublicKeyBase64();
        String privateKeyBase64 = asymmetricCrypto.getPrivateKeyBase64();

        return new KeyPair(publicKeyBase64, privateKeyBase64);
    }

    @Override
    public void updateStatus(ApiClientRequest apiClientRequest) {
        LambdaUpdateWrapper<ApiClient> apiClientLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        apiClientLambdaUpdateWrapper.eq(ApiClient::getApiClientId, apiClientRequest.getApiClientId());
        apiClientLambdaUpdateWrapper.set(ApiClient::getApiClientStatus, apiClientRequest.getApiClientStatus());
        this.update(apiClientLambdaUpdateWrapper);
    }

    @Override
    public void batchDelete(ApiClientRequest apiClientRequest) {
        this.removeByIds(apiClientRequest.getApiClientIdList());
    }

    @Override
    public ApiClient getByCode(String apiClientCode) {
        if (ObjectUtil.isEmpty(apiClientCode)) {
            return null;
        }

        LambdaUpdateWrapper<ApiClient> apiClientLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        apiClientLambdaUpdateWrapper.eq(ApiClient::getApiClientCode, apiClientCode);
        return this.getOne(apiClientLambdaUpdateWrapper, false);
    }

    @Override
    public String getApiClientSecret(Long apiClientId) {
        LambdaQueryWrapper<ApiClient> apiClientLambdaQueryWrapper = new LambdaQueryWrapper<>();
        apiClientLambdaQueryWrapper.eq(ApiClient::getApiClientId, apiClientId);
        apiClientLambdaQueryWrapper.eq(ApiClient::getApiClientStatus, StatusEnum.ENABLE.getCode());
        apiClientLambdaQueryWrapper.select(ApiClient::getApiClientSecret);
        ApiClient one = this.getOne(apiClientLambdaQueryWrapper, false);
        if (one == null) {
            return null;
        } else {
            return one.getApiClientSecret();
        }
    }

    @Override
    public List<ApiClient> findList(ApiClientRequest apiClientRequest) {
        LambdaQueryWrapper<ApiClient> wrapper = this.createWrapper(apiClientRequest);

        // 只查询名称和id
        wrapper.select(ApiClient::getApiClientName, ApiClient::getApiClientId);

        return this.list(wrapper);
    }

    /**
     * 获取信息
     *
     * @author fengshuonan
     * @since 2023/10/23 22:57
     */
    private ApiClient queryApiClient(ApiClientRequest apiClientRequest) {
        ApiClient apiClient = this.getById(apiClientRequest.getApiClientId());
        if (ObjectUtil.isEmpty(apiClient)) {
            throw new ServiceException(ApiClientExceptionEnum.API_CLIENT_NOT_EXISTED);
        }
        return apiClient;
    }

    /**
     * 创建查询wrapper
     *
     * @author fengshuonan
     * @since 2023/10/23 22:57
     */
    private LambdaQueryWrapper<ApiClient> createWrapper(ApiClientRequest apiClientRequest) {
        LambdaQueryWrapper<ApiClient> queryWrapper = new LambdaQueryWrapper<>();

        // 根据查询条件搜索
        String searchText = apiClientRequest.getSearchText();
        if (ObjectUtil.isNotEmpty(searchText)) {
            queryWrapper.like(ApiClient::getApiClientName, searchText);
            queryWrapper.or().like(ApiClient::getApiClientCode, searchText);
        }

        return queryWrapper;
    }

}
